// 1.接口：面向对象编程中表 示为行为的抽象，另外可以用来描述对象的形状
// 1.1 对象的形状 接口可以用来描述`对象的形状`,少属性或者多属性都会报
namespace a {
    interface Speak {
        name:string;
        speak():void
    }
    let spaakMan :Speak = {
        name:'ikki',
        speak(){}
    }
}

// 1.2 行为的抽象  接口可以在面向对象编程中表示为行为的抽象
// 同名的接口可以写多个，类型会自动合并
namespace b {
    interface Speakable{
        ha():void;
    }
    interface Speakable{
        speak():void;
    }
    interface Eatable{
        eat():void
    }
    class Person implements Speakable,Eatable {
        ha(): void {
            throw new Error("Method not implemented.");
        }
        speak(): void {
            throw new Error("Method not implemented.");
        }
        eat(): void {
            throw new Error("Method not implemented.");
        }
    }
}
// 1.3任意属性 无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
namespace c {
    interface Person {
        readonly id:number;
        name:string;
        [key:string]:any
    }
    let p : Person = {
        id:1,
        name:'ikki',
        age:27,
        11:23,
    }
}

// 2.接口的继承 一个接口可以继承自另外一个接口
namespace d {
    interface Speakable {
        speak(): void
    }
    interface SpeakChinese extends Speakable {
        speakChinese(): void
    }
    class Person implements SpeakChinese {
        speakChinese(): void {
            throw new Error("Method not implemented.");
        }
        speak(): void {
            throw new Error("Method not implemented.");
        }
    }
}

// 3.readonly   用 readonly 定义只读属性可以避免由于多人协作或者项目较为复杂等因素造成对象的值被重写
namespace f {
    interface Person{
        readonly id:number;
        name:string
      }
      let tom:Person = {
        id :1,
        name:'ikki'
      }
    //   tom.id = 1;  //Unable to compile TypeScript
}

// 4.函数类型接口:对函数传入的参数和返回值进行约束
namespace e {
    interface discount{
        (price:number):number
    }
    let disCount : discount = (price:number):number =>{
        return price*.8
    }
}

// 5.可索引接口:对数组和对象进行约束
namespace g {
    interface User {
        [xx:number]:string
    }
    let user:User = {
        0:'0',
        1:'1'
    }
    let arr1 :User = ['1','2']
}

// 6.类接口 : 对类的约束
namespace h {
    interface Speakable {
        name: string;
        speak(words: string): void
    }
    class Dog implements Speakable {
        name!: string;
        speak(words:string) {
            console.log(words);
        }
    }
    let dog = new Dog();
    dog.speak('汪汪汪');
}

// 7.构造函数的类型
// 在 TypeScript 中，我们可以用 interface 来描述类
// 同时也可以使用interface里特殊的new()关键字来描述类的构造函数类型
namespace r  {
    class Animal{
        constructor(public name:string){
        }
      }
    //不加new是修饰函数的,加new是修饰类的
    //   interface WithNameClass{
    //     (name:string):Animal
    //   }
      interface WithNameClass{
        new(name:string):Animal
      }
      function createAnimal(clazz:WithNameClass,name:string){
         return new clazz(name);
      }
      let a = createAnimal(Animal,'ikki');
      console.log(a.name);
}

// 8.抽象类 vs 接口区别
// 不同类之间公有的属性或方法，可以抽象成一个接口（Interfaces）
// 而抽象类是供其他类继承的基类，抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
// 抽象类本质是一个无法被实例化的类，其中能够实现方法和初始化属性，而接口仅能够用于描述,既不提供方法的实现，也不为属性进行初始化
// 一个类可以继承一个类或抽象类，但可以实现（implements）多个接口
// 抽象类也可以实现接口
// abstract class Animal{
//     name:string;
//     constructor(name:string){
//       this.name = name;
//     }
//     abstract speak():void;
//   }
// interface Flying{
//       fly():void
// }
// class Duck extends Animal implements Flying{
//       speak(){
//           console.log('汪汪汪');
//       }
//       fly(){
//           console.log('我会飞');
//       }
// }
// let duck = new Duck('ikki');
// duck.speak();
// duck.fly();